package com.supreme.uploadserver.component;

import com.supreme.commonboot.exception.BizException;
import com.supreme.uploadserver.component.props.MinioProps;
import io.minio.*;
import io.minio.errors.MinioException;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class MinIoService {

    @Resource
    private MinioProps minIoProps;

    private MinioClient minioClient;

    @PostConstruct
    public void init() {
        log.info("MinIoUtils {}", "init");
        try {
            minioClient = MinioClient.builder()
                    .endpoint(minIoProps.getHost(), minIoProps.getPort(), false)
                    .credentials(minIoProps.getAccessKey(), minIoProps.getSecretKey())
                    .build();
            createBucket(minIoProps.getBucketName());
        } catch (Exception e) {
            log.error("MinIoUtils Exception: {}", e.getMessage());
        }
    }

    /**
     * 判断 bucket是否存在
     *
     * @param bucketName: 桶名
     * @return: boolean
     */
    @SneakyThrows(Exception.class)
    public boolean bucketExists(String bucketName) {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    /**
     * 创建 bucket
     *
     * @param bucketName: 桶名
     * @return: void
     */
    @SneakyThrows(Exception.class)
    public void createBucket(String bucketName) {
        BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
        boolean isExist = minioClient.bucketExists(bucketExistsArgs);
        if (!isExist) {
            MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build();
            minioClient.makeBucket(makeBucketArgs);
        }
    }

    /**
     * 创建 bucket
     *
     * @param bucketName: 桶名
     * @return: void
     */
    @SneakyThrows(Exception.class)
    public void removeBucket(String bucketName) {
        BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
        boolean isExist = minioClient.bucketExists(bucketExistsArgs);
        if (isExist) {
            final RemoveBucketArgs removeBucketArgs = RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build();
            minioClient.removeBucket(removeBucketArgs);
        }
    }

    /**
     * 获取全部bucket
     */
    @SneakyThrows(Exception.class)
    public List<Bucket> getBucketList() {
        return minioClient.listBuckets();
    }

    /**
     * 文件上传
     *
     * @param bucketName: 桶名
     * @param fileName: 文件名
     * @param filePath: 文件路径
     * @return: ObjectWriteResponses
     */
    @SneakyThrows(Exception.class)
    public void upload(String bucketName, String fileName, String filePath, String contentType) {
        try {
            final UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .filename(filePath)
                    .contentType(contentType)
                    .build();
            minioClient.uploadObject(uploadObjectArgs);
        } catch (MinioException e) {
            throw new BizException(e.getMessage());
        }
    }

    /**
     * 文件上传
     *
     * @param bucketName: 桶名
     * @param fileName: 文件名
     * @param stream: 文件流
     * @return: java.lang.String : 文件url地址
     */
    @SneakyThrows(Exception.class)
    public void upload(String bucketName, String fileName, InputStream stream, long fileSize, String contentType) {
        final PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .stream(stream, fileSize, -1)
                .contentType(contentType)
                .build();
        minioClient.putObject(putObjectArgs);
    }

    /**
     * 删除文件
     *
     * @param bucketName: 桶名
     * @param fileName: 文件名
     * @return: void
     */
    @SneakyThrows(Exception.class)
    public void deleteFile(String bucketName, String fileName) {
        final RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .build();
        minioClient.removeObject(removeObjectArgs);
    }

    /**
     * 下载文件
     *
     * @param bucketName: 桶名
     * @param fileName: 文件名
     * @param response:
     * @return: void
     */
    /*@SneakyThrows(Exception.class)
    public static void download(String bucketName, String fileName, HttpServletResponse response) {
        // 获取对象的元数据
        final ObjectStat stat = minioClient.statObject(bucketName, fileName);
        response.setContentType(stat.contentType());
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        InputStream is = minioClient.getObject(bucketName, fileName);
        IOUtils.copy(is, response.getOutputStream());
        is.close();
    }*/

    /**
     * 获取minio Object
     *
     * @param bucketName: 桶名
     * @param fileName: 文件名
     * @return: java.lang.String
     */
    @SneakyThrows(Exception.class)
    public String getObject(String bucketName, String fileName) {
        final GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .build();
        final GetObjectResponse getObjectRes = minioClient.getObject(getObjectArgs);
        return getObjectRes.object();
    }

    /**
     * 获取minio Object List
     *
     * @param bucketName: 桶名
     * @return: java.lang.String
     */
    @SneakyThrows(Exception.class)
    public List<String> getObjectList(String bucketName) {
        final ListObjectsArgs listObjectsArgs = ListObjectsArgs.builder()
                .bucket(bucketName)
                .build();

        List<String> fileList = new ArrayList<>();
        final Iterable<Result<Item>> objectList = minioClient.listObjects(listObjectsArgs);
        for (Result<Item> itemResult : objectList) {
            final Item item = itemResult.get();
            fileList.add(item.objectName());
        }

        return fileList;
    }

    /**
     * 获取minio文件的下载地址
     *
     * @param bucketName: 桶名
     * @param fileName: 文件名
     * @return: java.lang.String
     */
    @SneakyThrows(Exception.class)
    public String getFileUrl(String bucketName, String fileName, int expireSecond) {
        final GetPresignedObjectUrlArgs objectUrlArgs = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .method(Method.GET)
                .expiry(expireSecond, TimeUnit.SECONDS)
                .build();
        return minioClient.getPresignedObjectUrl(objectUrlArgs);
    }
}
